#pragma once
#include <iostream>
#include <string>
#include <vector>
#include "Sem.hpp"
#include <pthread.h>
#include "Mutex.hpp"

const int defaultcap = 5;
using namespace MyMutex;

template <typename T>
class RingQueue
{
public:
    RingQueue(int cap = defaultcap)
        : _cap(cap), _c_step(0), _p_step(0), _blank_sem(cap), _data_sem(0)
    {
    }

    void Enqueue(const T &in)
    {
        _blank_sem.P();
        {
            LockGuard plock(_p_mutex);
            _ring_queue[_p_step++] = in;
            _p_step %= _cap;
        }
        _blank_sem.V();
    }

    void Popqueue(T *out)
    {
        _data_sem.P();
        {
            LockGuard Clock(_c_mutex);
            *out = _ring_queue[_c_step++];
            _c_step %= _cap;
        }
        _data_sem.V();
    }

    ~RingQueue() {}

private:
    std::vector<T> _ring_queue;
    int _cap;

    int _c_step;
    int _p_step;

    Sem _blank_sem;
    Sem _data_sem;

    Mutex _p_mutex;
    Mutex _c_mutex;
};